03 常量的使用与应用规范
常量
- 常量(
constant)用于表示在程序执行期间其值保持不变的量。 - 常量使用
const关键字进行声明,并且只能存储基本类型(如布尔、数字、字符串等)的值。
语法
go
const identifier [type] = valueidentifier是常量的名称。type是可选的常量类型(通常会被自动推断)。value是常量的值,一旦设置就不能更改。
go
package main
import "fmt"
const PI = 3.14 // 定义浮点型常量
const Greeting string = "Hello, Go!" // 定义字符串常量
func main() {
fmt.Println("PI:", PI)
fmt.Println(Greeting)
}常量与变量的区别
常量 (const) | 变量 (var) |
|---|---|
| 值在编译时确定 | 值可以在运行时改变 |
| 只能使用基本类型(字符串、布尔、数字类型) | 可以是任何类型,包括结构体、数组、切片等 |
| 不能被修改 | 可以在程序执行过程中动态修改 |
只能使用 const 关键字声明 | 可以使用 var 或简短声明 := |
| 不能调用函数赋值 | 可以调用函数返回值赋值 |
多个常量声明
常量可以分组声明,用括号将多条 const 语句包围在一起:
go
const (
A = 1
B = 2
C = 3
)
// 指定类型或初始化不同类型的常量
const (
X int = 10
Y float64 = 20.5
Z = "Go Language"
)使用 iota 枚举
Go 语言提供了一个名为 iota 的特殊常量,它可以用于简化一系列相关常量的声明,并自动生成递增的值。iota 初始值为 0,每声明一个常量,iota 的值会自动递增。
常见的使用场景:定义枚举值、位移常量等。
go
package main
import "fmt"
// 使用 iota 生成一组枚举常量
const (
Apple = iota // Apple 的值是 0
Banana // Banana 的值是 1
Cherry // Cherry 的值是 2
)
func main() {
// iota 的值从 0 开始,并在每行自动递增,所以 Apple, Banana, Cherry 分别是 0, 1, 2
fmt.Println(Apple, Banana, Cherry) // 输出:0 1 2
}更复杂的 iota 用法
iota 可以用于生成复杂的常量序列,例如按位移的值(位掩码):KB、MB、GB 分别表示 1 KB、1 MB 和 1 GB 的字节数,通过 iota 和位运算轻松实现了字节单位的转换。
go
const (
_ = iota // 跳过 iota = 0
KB = 1 << (10 * iota) // 1 左移 10 位,等于 1024
MB = 1 << (10 * iota) // 1 左移 20 位
GB = 1 << (10 * iota) // 1 左移 30 位
)
func main() {
fmt.Println("KB:", KB) // 1024
fmt.Println("MB:", MB) // 1048576
fmt.Println("GB:", GB) // 1073741824
}使用常量定义错误代码、配置值
常量通常用于定义程序中的固定值,例如:
- 错误代码
- 配置参数
- 枚举类型
- 状态标识
go
package main
import "fmt"
// 定义错误代码常量
const (
ErrNotFound = 404
ErrUnauthorized = 401
ErrServerError = 500
)
func main() {
fmt.Println("Not Found Error Code:", ErrNotFound)
fmt.Println("Unauthorized Error Code:", ErrUnauthorized)
fmt.Println("Server Error Code:", ErrServerError)
}有类型常量
- 使用 const 声明常量,并且指定常量的类型。
- 缺点:不简洁。
go
package main
import "fmt"
type MyInt int
const X MyInt = 10
// const x int = 11 + X // 需要显式转换,否则编译错误
const x int = 11 + int(X)
// const y int = X // 需要显式转换,否则编译错误
const y int = int(X)
const z MyInt = X // 或者将两个生命为同一个类型
func main() {
const PI float64 = 3.14
fmt.Println("PI:", PI)
fmt.Println("x:", x)
fmt.Println("y:", y)
fmt.Println("z:", z)
var radius float64 = 5.0
var perimeter = 2 * PI * radius // 有类型常量 PI 是 float64 类型
fmt.Printf("Perimeter: %f\n", perimeter)
var diameter int = 10
// 以下语句会报错,因为 PI 是 float64 类型,不能直接用于 int 类型的计算
// var circumference = 2 * PI * diameter
fmt.Println("diameter:", diameter)
}bash
❯ go run typed_constant.go
PI: 3.14
x: 21
y: 10
z: 10
Perimeter: 31.400000
diameter: 10无类型常量
- 使用 const 声明常量,不指定常量的类型。
- 优点:灵活,可以自动推断类型。
go
package main
import "fmt"
const PI = 3.14
// 使用 iota 定义一组无类型整型常量
// 由于 iota 生成的常量没有明确类型,可以根据上下文推断为 int 或其他数值类型,这样可以在多种表达式中灵活使用
const (
Apple = iota
Banana
Cherry
)
func main() {
var radius float64 = 5.0
var perimeter = 2 * PI * radius // 无类型常量 PI 被推断为 float64
fmt.Printf("Perimeter: %f\n", perimeter)
var diameter int = 10
var circumference = 2 * PI * float64(diameter) // PI 被推断为 float64 后转换
fmt.Printf("Circumference: %f\n", circumference)
fmt.Printf("Apple: %d\t Banana: %d\t Cherry: %d\n", Apple, Banana, Cherry)
}bash
❯ go run untyped_constant.go
Perimeter: 31.400000
Circumference: 62.800000
Apple: 0 Banana: 1 Cherry: 2无类型常量与有类型常量的区别
| 无类型常量(Untyped Constants) | 有类型常量(Typed Constants) |
|---|---|
| 在声明时没有指定类型 | 在声明时明确指定了类型 |
| 在使用时根据上下文自动推断类型 | 类型固定,不会因为使用场景而改变 |
可以在不同的上下文中用作不同类型(如 int、float64) | 只能用于声明类型一致的表达式中 |
| 常用于需要灵活转换类型的场景 | 常用于防止类型混淆和确保类型一致性 |
例如:const Pi = 3.14 | 例如:const Pi float64 = 3.14 |
go
package main
import "fmt"
// 无类型常量
const (
A = 10 // 无类型整型常量
B = 3.14 // 无类型浮点型常量
)
// 有类型常量
const (
C int = 10 // 有类型整型常量
D float64 = 3.14 // 有类型浮点型常量
)
func main() {
// 无类型常量可以与不同类型的变量混合运算
var x int = A // A 自动推断为 int 类型
var y float64 = A // A 可以被自动推断为 float64 类型
fmt.Println("x:", x) // 输出:x: 10
fmt.Println("y:", y) // 输出:y: 10.000000
// 有类型常量只能用于相同类型的变量
var z int = C // C 是 int 类型,可以赋值给 int 类型变量
// var w float64 = C // 这里会报错,因为 C 是 int 类型,不能自动转换为 float64 类型
var radius float64 = 5.0
fmt.Println("Circumference:", 2*B*radius) // B 被推断为 float64 类型
}